c------------------------------------------------------------- subroutine local_move_init(debug) crc implicit none c Includes implicit real*8 (a-h,o-z) include 'DIMENSIONS' ! Needed by COMMON.LOCAL include 'COMMON.GEO' ! For pi, deg2rad include 'COMMON.LOCAL' ! For vbl include 'COMMON.LOCMOVE' c INPUT arguments logical debug c Determine wheter to do some debugging output locmove_output=debug c Set the init_called flag to 1 init_called=1 c The following are never changed min_theta=60.D0*deg2rad ! (0,PI) max_theta=175.D0*deg2rad ! (0,PI) dmin2=vbl*vbl*2.*(1.-cos(min_theta)) dmax2=vbl*vbl*2.*(1.-cos(max_theta)) flag=1.0D300 small=1.0D-5 small2=0.5*small*small c Not really necessary... a_n=0 b_n=0 res_n=0 return end c------------------------------------------------------------- subroutine local_move(n_start, n_end, PHImin, PHImax) c Perform a local move between residues m and n (inclusive) c PHImin and PHImax [0,PI] determine the size of the move c Works on whatever structure is in the variables theta and phi, c sidechain variables are left untouched c The final structure is NOT minimized, but both the cartesian c variables c and the angles are up-to-date at the end (no further c chainbuild is required) crc implicit none c Includes implicit real*8 (a-h,o-z) include 'DIMENSIONS' include 'COMMON.GEO' include 'COMMON.CHAIN' include 'COMMON.VAR' include 'COMMON.MINIM' include 'COMMON.SBRIDGE' include 'COMMON.LOCMOVE' c External functions integer move_res external move_res double precision ran_number external ran_number c INPUT arguments integer n_start, n_end ! First and last residues to move double precision PHImin, PHImax ! min/max angles [0,PI] c Local variables integer i,j double precision min,max integer iretcode c Check if local_move_init was called. This assumes that it c would not be 1 if not explicitely initialized if (init_called.ne.1) then write(6,*)' *** local_move_init not called!!!' stop endif c Quick check for crazy range if (n_start.gt.n_end .or. n_start.lt.1 .or. n_end.gt.nres) then write(6,'(a,i3,a,i3)') + ' *** Cannot make local move between n_start = ', + n_start,' and n_end = ',n_end return endif c Take care of end residues first... if (n_start.eq.1) then c Move residue 1 (completely random) theta(3)=ran_number(min_theta,max_theta) phi(4)=ran_number(-PI,PI) i=2 else i=n_start endif if (n_end.eq.nres) then c Move residue nres (completely random) theta(nres)=ran_number(min_theta,max_theta) phi(nres)=ran_number(-PI,PI) j=nres-1 else j=n_end endif c ...then go through all other residues one by one c Start from the two extremes and converge call chainbuild do while (i.le.j) min=PHImin max=PHImax c$$$c Move the first two residues by less than the others c$$$ if (i-n_start.lt.3) then c$$$ if (i-n_start.eq.0) then c$$$ min=0.4*PHImin c$$$ max=0.4*PHImax c$$$ else if (i-n_start.eq.1) then c$$$ min=0.8*PHImin c$$$ max=0.8*PHImax c$$$ else if (i-n_start.eq.2) then c$$$ min=PHImin c$$$ max=PHImax c$$$ endif c$$$ endif c The actual move, on residue i iretcode=move_res(min,max,i,c) ! Discard iretcode i=i+1 if (i.le.j) then min=PHImin max=PHImax c$$$c Move the last two residues by less than the others c$$$ if (n_end-j.lt.3) then c$$$ if (n_end-j.eq.0) then c$$$ min=0.4*PHImin c$$$ max=0.4*PHImax c$$$ else if (n_end-j.eq.1) then c$$$ min=0.8*PHImin c$$$ max=0.8*PHImax c$$$ else if (n_end-j.eq.2) then c$$$ min=PHImin c$$$ max=PHImax c$$$ endif c$$$ endif c The actual move, on residue j iretcode=move_res(min,max,j,c) ! Discard iretcode j=j-1 endif enddo call int_from_cart(.false.,.false.) return end c------------------------------------------------------------- subroutine output_tabs c Prints out the contents of a_..., b_..., res_... implicit none c Includes include 'COMMON.GEO' include 'COMMON.LOCMOVE' c Local variables integer i,j write(6,*)'a_...' write(6,'(8f7.1)')(a_ang(i)*rad2deg,i=0,a_n-1) write(6,'(8(2x,3l1,2x))')((a_tab(i,j),i=0,2),j=0,a_n-1) write(6,*)'b_...' write(6,'(4f7.1)')(b_ang(i)*rad2deg,i=0,b_n-1) write(6,'(4(2x,3l1,2x))')((b_tab(i,j),i=0,2),j=0,b_n-1) write(6,*)'res_...' write(6,'(12f7.1)')(res_ang(i)*rad2deg,i=0,res_n-1) write(6,'(12(2x,3l1,2x))')((res_tab(0,i,j),i=0,2),j=0,res_n-1) write(6,'(12(2x,3l1,2x))')((res_tab(1,i,j),i=0,2),j=0,res_n-1) write(6,'(12(2x,3l1,2x))')((res_tab(2,i,j),i=0,2),j=0,res_n-1) return end c------------------------------------------------------------- subroutine angles2tab(PHImin,PHImax,n,ang,tab) c Only uses angles if [0,PI] (but PHImin cannot be 0., c and PHImax cannot be PI) implicit none c Includes include 'COMMON.GEO' c INPUT arguments double precision PHImin,PHImax c OUTPUT arguments integer n double precision ang(0:3) logical tab(0:2,0:3) if (PHImin .eq. PHImax) then c Special case with two 010's n = 2; ang(0) = -PHImin; ang(1) = PHImin; tab(0,0) = .false. tab(2,0) = .false. tab(0,1) = .false. tab(2,1) = .false. tab(1,0) = .true. tab(1,1) = .true. else if (PHImin .eq. PI) then c Special case with one 010 n = 1 ang(0) = PI tab(0,0) = .false. tab(2,0) = .false. tab(1,0) = .true. else if (PHImax .eq. 0.) then c Special case with one 010 n = 1 ang(0) = 0. tab(0,0) = .false. tab(2,0) = .false. tab(1,0) = .true. else c Standard cases n = 0 if (PHImin .gt. 0.) then c Start of range (011) ang(n) = PHImin tab(0,n) = .false. tab(1,n) = .true. tab(2,n) = .true. c End of range (110) ang(n+1) = -PHImin tab(0,n+1) = .true. tab(1,n+1) = .true. tab(2,n+1) = .false. n = n+2 endif if (PHImax .lt. PI) then c Start of range (011) ang(n) = -PHImax tab(0,n) = .false. tab(1,n) = .true. tab(2,n) = .true. c End of range (110) ang(n+1) = PHImax tab(0,n+1) = .true. tab(1,n+1) = .true. tab(2,n+1) = .false. n = n+2 endif endif return end c------------------------------------------------------------- subroutine minmax_angles(x,y,z,r,n,ang,tab) c When solutions do not exist, assume all angles c are acceptable - i.e., initial geometry must be correct implicit none c Includes include 'COMMON.GEO' include 'COMMON.LOCMOVE' c Input arguments double precision x,y,z,r c Output arguments integer n double precision ang(0:3) logical tab(0:2,0:3) c Local variables double precision num, denom, phi double precision Kmin, Kmax integer i num = x*x + y*y + z*z denom = x*x + y*y n = 0 if (denom .gt. 0.) then phi = atan2(y,x) denom = 2.*r*sqrt(denom) num = num+r*r Kmin = (num - dmin2)/denom Kmax = (num - dmax2)/denom c Allowed values of K (else all angles are acceptable) c -1 <= Kmin < 1 c -1 < Kmax <= 1 if (Kmin .gt. 1. .or. abs(Kmin-1.) .lt. small2) then Kmin = -flag else if (Kmin .lt. -1. .or. abs(Kmin+1.) .lt. small2) then Kmin = PI else Kmin = acos(Kmin) endif if (Kmax .lt. -1. .or. abs(Kmax+1.) .lt. small2) then Kmax = flag else if (Kmax .gt. 1. .or. abs(Kmax-1.) .lt. small2) then Kmax = 0. else Kmax = acos(Kmax) endif if (Kmax .lt. Kmin) Kmax = Kmin call angles2tab(Kmin, Kmax, n, ang, tab) c Add phi and check that angles are within range (-PI,PI] do i=0,n-1 ang(i) = ang(i)+phi if (ang(i) .le. -PI) then ang(i) = ang(i)+2.*PI else if (ang(i) .gt. PI) then ang(i) = ang(i)-2.*PI endif enddo endif return end c------------------------------------------------------------- subroutine construct_tab c Take a_... and b_... values and produces the results res_... c x_ang are assumed to be all different (diff > small) c x_tab(1,i) must be 1 for all i (i.e., all x_ang are acceptable) implicit none c Includes include 'COMMON.LOCMOVE' c Local variables integer n_max,i,j,index logical done double precision phi n_max = a_n + b_n if (n_max .eq. 0) then res_n = 0 return endif do i=0,n_max-1 do j=0,1 res_tab(j,0,i) = .true. res_tab(j,2,i) = .true. res_tab(j,1,i) = .false. enddo enddo index = 0 phi = -flag done = .false. do while (.not.done) res_ang(index) = flag c Check a first... do i=0,a_n-1 if ((a_ang(i)-phi).gt.small .and. + a_ang(i) .lt. res_ang(index)) then c Found a lower angle res_ang(index) = a_ang(i) c Copy the values from a_tab into res_tab(0,,) res_tab(0,0,index) = a_tab(0,i) res_tab(0,1,index) = a_tab(1,i) res_tab(0,2,index) = a_tab(2,i) c Set default values for res_tab(1,,) res_tab(1,0,index) = .true. res_tab(1,1,index) = .false. res_tab(1,2,index) = .true. else if (abs(a_ang(i)-res_ang(index)).lt.small) then c Found an equal angle (can only be equal to a b_ang) res_tab(0,0,index) = a_tab(0,i) res_tab(0,1,index) = a_tab(1,i) res_tab(0,2,index) = a_tab(2,i) endif enddo c ...then check b do i=0,b_n-1 if ((b_ang(i)-phi).gt.small .and. + b_ang(i) .lt. res_ang(index)) then c Found a lower angle res_ang(index) = b_ang(i) c Copy the values from b_tab into res_tab(1,,) res_tab(1,0,index) = b_tab(0,i) res_tab(1,1,index) = b_tab(1,i) res_tab(1,2,index) = b_tab(2,i) c Set default values for res_tab(0,,) res_tab(0,0,index) = .true. res_tab(0,1,index) = .false. res_tab(0,2,index) = .true. else if (abs(b_ang(i)-res_ang(index)).lt.small) then c Found an equal angle (can only be equal to an a_ang) res_tab(1,0,index) = b_tab(0,i) res_tab(1,1,index) = b_tab(1,i) res_tab(1,2,index) = b_tab(2,i) endif enddo if (res_ang(index) .eq. flag) then res_n = index done = .true. else if (index .eq. n_max-1) then res_n = n_max done = .true. else phi = res_ang(index) ! Store previous angle index = index+1 endif enddo c Fill the gaps c First a... index = 0 if (a_n .gt. 0) then do while (.not.res_tab(0,1,index)) index=index+1 enddo done = res_tab(0,2,index) do i=index+1,res_n-1 if (res_tab(0,1,i)) then done = res_tab(0,2,i) else res_tab(0,0,i) = done res_tab(0,1,i) = done res_tab(0,2,i) = done endif enddo done = res_tab(0,0,index) do i=index-1,0,-1 if (res_tab(0,1,i)) then done = res_tab(0,0,i) else res_tab(0,0,i) = done res_tab(0,1,i) = done res_tab(0,2,i) = done endif enddo else do i=0,res_n-1 res_tab(0,0,i) = .true. res_tab(0,1,i) = .true. res_tab(0,2,i) = .true. enddo endif c ...then b index = 0 if (b_n .gt. 0) then do while (.not.res_tab(1,1,index)) index=index+1 enddo done = res_tab(1,2,index) do i=index+1,res_n-1 if (res_tab(1,1,i)) then done = res_tab(1,2,i) else res_tab(1,0,i) = done res_tab(1,1,i) = done res_tab(1,2,i) = done endif enddo done = res_tab(1,0,index) do i=index-1,0,-1 if (res_tab(1,1,i)) then done = res_tab(1,0,i) else res_tab(1,0,i) = done res_tab(1,1,i) = done res_tab(1,2,i) = done endif enddo else do i=0,res_n-1 res_tab(1,0,i) = .true. res_tab(1,1,i) = .true. res_tab(1,2,i) = .true. enddo endif c Finally fill the last row with AND operation do i=0,res_n-1 do j=0,2 res_tab(2,j,i) = (res_tab(0,j,i) .and. res_tab(1,j,i)) enddo enddo return end c------------------------------------------------------------- subroutine construct_ranges(phi_n,phi_start,phi_end) c Given the data in res_..., construct a table of c min/max allowed angles implicit none c Includes include 'COMMON.GEO' include 'COMMON.LOCMOVE' c Output arguments integer phi_n double precision phi_start(0:11),phi_end(0:11) c Local variables logical done integer index if (res_n .eq. 0) then c Any move is allowed phi_n = 1 phi_start(0) = -PI phi_end(0) = PI else phi_n = 0 index = 0 done = .false. do while (.not.done) c Find start of range (01x) done = .false. do while (.not.done) if (res_tab(2,0,index).or.(.not.res_tab(2,1,index))) then index=index+1 else done = .true. phi_start(phi_n) = res_ang(index) endif if (index .eq. res_n) done = .true. enddo c If a start was found (index < res_n), find the end of range (x10) c It may not be found without wrapping around if (index .lt. res_n) then done = .false. do while (.not.done) if ((.not.res_tab(2,1,index)).or.res_tab(2,2,index)) then index=index+1 else done = .true. endif if (index .eq. res_n) done = .true. enddo if (index .lt. res_n) then c Found the end of the range phi_end(phi_n) = res_ang(index) phi_n=phi_n+1 index=index+1 if (index .eq. res_n) then done = .true. else done = .false. endif else c Need to wrap around done = .true. phi_end(phi_n) = flag endif endif enddo c Take care of the last one if need to wrap around if (phi_end(phi_n) .eq. flag) then index = 0 do while ((.not.res_tab(2,1,index)).or.res_tab(2,2,index)) index=index+1 enddo phi_end(phi_n) = res_ang(index) + 2.*PI phi_n=phi_n+1 endif endif return end c------------------------------------------------------------- subroutine fix_no_moves(phi) implicit none c Includes include 'COMMON.GEO' include 'COMMON.LOCMOVE' c Output arguments double precision phi c Local variables integer index double precision diff,temp c Look for first 01x in gammas (there MUST be at least one) diff = flag index = 0 do while (res_tab(1,0,index) .or. (.not.res_tab(1,1,index))) index=index+1 enddo if (res_ang(index) .le. 0.D0) then ! Make sure it's from PHImax c Try to increase PHImax if (index .gt. 0) then phi = res_ang(index-1) diff = abs(res_ang(index) - res_ang(index-1)) endif c Look for last (corresponding) x10 index = res_n - 1 do while ((.not.res_tab(1,1,index)) .or. res_tab(1,2,index)) index=index-1 enddo if (index .lt. res_n-1) then temp = abs(res_ang(index) - res_ang(index+1)) if (temp .lt. diff) then phi = res_ang(index+1) diff = temp endif endif endif c If increasing PHImax didn't work, decreasing PHImin c will (with one exception) c Look for first x10 (there MUST be at least one) index = 0 do while ((.not.res_tab(1,1,index)) .or. res_tab(1,2,index)) index=index+1 enddo if (res_ang(index) .lt. 0.D0) then ! Make sure it's from PHImin c Try to decrease PHImin if (index .lt. res_n-1) then temp = abs(res_ang(index) - res_ang(index+1)) if (res_ang(index+1) .le. 0.D0 .and. temp .lt. diff) then phi = res_ang(index+1) diff = temp endif endif c Look for last (corresponding) 01x index = res_n - 1 do while (res_tab(1,0,index) .or. (.not.res_tab(1,1,index))) index=index-1 enddo if (index .gt. 0) then temp = abs(res_ang(index) - res_ang(index-1)) if (res_ang(index-1) .ge. 0.D0 .and. temp .lt. diff) then phi = res_ang(index-1) diff = temp endif endif endif c If it still didn't work, it must be PHImax == 0. or PHImin == PI if (diff .eq. flag) then index = 0 if (res_tab(index,1,0) .or. (.not.res_tab(index,1,1)) .or. + res_tab(index,1,2)) index = res_n - 1 c This MUST work at this point if (index .eq. 0) then phi = res_ang(1) else phi = res_ang(index - 1) endif endif return end c------------------------------------------------------------- integer function move_res(PHImin,PHImax,i_move) c Moves residue i_move (in array c), leaving everything else fixed c Starting geometry is not checked, it should be correct! c R(,i_move) is the only residue that will move, but must have c 1 < i_move < nres (i.e., cannot move ends) c Whether any output is done is controlled by locmove_output crc implicit none c Includes implicit real*8 (a-h,o-z) include 'DIMENSIONS' include 'COMMON.CHAIN' include 'COMMON.GEO' include 'COMMON.LOCMOVE' c External functions double precision ran_number external ran_number c Input arguments double precision PHImin,PHImax integer i_move c RETURN VALUES: c 0: move successfull c 1: Dmin or Dmax had to be modified c 2: move failed - check your input geometry c Local variables double precision X(0:2),Y(0:2),Z(0:2),Orig(0:2) double precision P(0:2) logical no_moves,done integer index,i,j double precision phi,temp,radius double precision phi_start(0:11), phi_end(0:11) integer phi_n c Set up the coordinate system do i=0,2 Orig(i)=0.5*(c(i+1,i_move-1)+c(i+1,i_move+1)) ! Position of origin enddo do i=0,2 Z(i)=c(i+1,i_move+1)-c(i+1,i_move-1) enddo temp=sqrt(Z(0)*Z(0)+Z(1)*Z(1)+Z(2)*Z(2)) do i=0,2 Z(i)=Z(i)/temp enddo do i=0,2 X(i)=c(i+1,i_move)-Orig(i) enddo c radius is the radius of the circle on which c(,i_move) can move radius=sqrt(X(0)*X(0)+X(1)*X(1)+X(2)*X(2)) do i=0,2 X(i)=X(i)/radius enddo Y(0)=Z(1)*X(2)-X(1)*Z(2) Y(1)=X(0)*Z(2)-Z(0)*X(2) Y(2)=Z(0)*X(1)-X(0)*Z(1) c Calculate min, max angles coming from dmin, dmax to c(,i_move-2) if (i_move.gt.2) then do i=0,2 P(i)=c(i+1,i_move-2)-Orig(i) enddo call minmax_angles(P(0)*X(0)+P(1)*X(1)+P(2)*X(2), + P(0)*Y(0)+P(1)*Y(1)+P(2)*Y(2), + P(0)*Z(0)+P(1)*Z(1)+P(2)*Z(2), + radius,a_n,a_ang,a_tab) else a_n=0 endif c Calculate min, max angles coming from dmin, dmax to c(,i_move+2) if (i_move.lt.nres-2) then do i=0,2 P(i)=c(i+1,i_move+2)-Orig(i) enddo call minmax_angles(P(0)*X(0)+P(1)*X(1)+P(2)*X(2), + P(0)*Y(0)+P(1)*Y(1)+P(2)*Y(2), + P(0)*Z(0)+P(1)*Z(1)+P(2)*Z(2), + radius,b_n,b_ang,b_tab) else b_n=0 endif c Construct the resulting table for alpha and beta call construct_tab() if (locmove_output) then print *,'ALPHAS & BETAS TABLE' call output_tabs() endif c Check that there is at least one possible move no_moves = .true. if (res_n .eq. 0) then no_moves = .false. else index = 0 do while ((index .lt. res_n) .and. no_moves) if (res_tab(2,1,index)) no_moves = .false. index=index+1 enddo endif if (no_moves) then if (locmove_output) print *,' *** Cannot move anywhere' move_res=2 return endif c Transfer res_... into a_... a_n = 0 do i=0,res_n-1 if ( (res_tab(2,0,i).neqv.res_tab(2,1,i)) .or. + (res_tab(2,0,i).neqv.res_tab(2,2,i)) ) then a_ang(a_n) = res_ang(i) do j=0,2 a_tab(j,a_n) = res_tab(2,j,i) enddo a_n=a_n+1 endif enddo c Check that the PHI's are within [0,PI] if (PHImin .lt. 0. .or. abs(PHImin) .lt. small) PHImin = -flag if (PHImin .gt. PI .or. abs(PHImin-PI) .lt. small) PHImin = PI if (PHImax .gt. PI .or. abs(PHImax-PI) .lt. small) PHImax = flag if (PHImax .lt. 0. .or. abs(PHImax) .lt. small) PHImax = 0. if (PHImax .lt. PHImin) PHImax = PHImin c Calculate min and max angles coming from PHImin and PHImax, c and put them in b_... call angles2tab(PHImin, PHImax, b_n, b_ang, b_tab) c Construct the final table call construct_tab() if (locmove_output) then print *,'FINAL TABLE' call output_tabs() endif c Check that there is at least one possible move no_moves = .true. if (res_n .eq. 0) then no_moves = .false. else index = 0 do while ((index .lt. res_n) .and. no_moves) if (res_tab(2,1,index)) no_moves = .false. index=index+1 enddo endif if (no_moves) then c Take care of the case where no solution exists... call fix_no_moves(phi) if (locmove_output) then print *,' *** Had to modify PHImin or PHImax' print *,'phi: ',phi*rad2deg endif move_res=1 else c ...or calculate the solution c Construct phi_start/phi_end arrays call construct_ranges(phi_n, phi_start, phi_end) c Choose random angle phi in allowed range(s) temp = 0. do i=0,phi_n-1 temp = temp + phi_end(i) - phi_start(i) enddo phi = ran_number(phi_start(0),phi_start(0)+temp) index = 0 done = .false. do while (.not.done) if (phi .lt. phi_end(index)) then done = .true. else index=index+1 endif if (index .eq. phi_n) then done = .true. else if (.not.done) then phi = phi + phi_start(index) - phi_end(index-1) endif enddo if (index.eq.phi_n) phi=phi_end(phi_n-1) ! Fix numerical errors if (phi .gt. PI) phi = phi-2.*PI if (locmove_output) then print *,'ALLOWED RANGE(S)' do i=0,phi_n-1 print *,phi_start(i)*rad2deg,phi_end(i)*rad2deg enddo print *,'phi: ',phi*rad2deg endif move_res=0 endif c Re-use radius as temp variable temp=radius*cos(phi) radius=radius*sin(phi) do i=0,2 c(i+1,i_move)=Orig(i)+temp*X(i)+radius*Y(i) enddo return end c------------------------------------------------------------- subroutine loc_test crc implicit none c Includes implicit real*8 (a-h,o-z) include 'DIMENSIONS' include 'COMMON.GEO' include 'COMMON.LOCAL' include 'COMMON.LOCMOVE' c External functions integer move_res external move_res c Local variables integer i,j integer phi_n double precision phi_start(0:11),phi_end(0:11) double precision phi double precision R(0:2,0:5) locmove_output=.true. c call angles2tab(30.*deg2rad,70.*deg2rad,a_n,a_ang,a_tab) c call angles2tab(80.*deg2rad,130.*deg2rad,b_n,b_ang,b_tab) c call minmax_angles(0.D0,3.8D0,0.D0,3.8D0,b_n,b_ang,b_tab) c call construct_tab c call output_tabs c call construct_ranges(phi_n,phi_start,phi_end) c do i=0,phi_n-1 c print *,phi_start(i)*rad2deg,phi_end(i)*rad2deg c enddo c call fix_no_moves(phi) c print *,'NO MOVES FOUND, BEST PHI IS',phi*rad2deg R(0,0)=0.D0 R(1,0)=0.D0 R(2,0)=0.D0 R(0,1)=0.D0 R(1,1)=-cos(28.D0*deg2rad) R(2,1)=-0.5D0-sin(28.D0*deg2rad) R(0,2)=0.D0 R(1,2)=0.D0 R(2,2)=-0.5D0 R(0,3)=cos(30.D0*deg2rad) R(1,3)=0.D0 R(2,3)=0.D0 R(0,4)=0.D0 R(1,4)=0.D0 R(2,4)=0.5D0 R(0,5)=0.D0 R(1,5)=cos(26.D0*deg2rad) R(2,5)=0.5D0+sin(26.D0*deg2rad) do i=1,5 do j=0,2 R(j,i)=vbl*R(j,i) enddo enddo i=move_res(R(0,1),0.D0*deg2rad,180.D0*deg2rad) print *,'RETURNED ',i print *,(R(i,3)/vbl,i=0,2) return end c-------------------------------------------------------------