Line data Source code
1 : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 : Copyright (c) 2015-2023 The plumed team
3 : (see the PEOPLE file at the root of the distribution for a list of names)
4 :
5 : See http://www.plumed.org for more information.
6 :
7 : This file is part of plumed, version 2.
8 :
9 : plumed is free software: you can redistribute it and/or modify
10 : it under the terms of the GNU Lesser General Public License as published by
11 : the Free Software Foundation, either version 3 of the License, or
12 : (at your option) any later version.
13 :
14 : plumed is distributed in the hope that it will be useful,
15 : but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : GNU Lesser General Public License for more details.
18 :
19 : You should have received a copy of the GNU Lesser General Public License
20 : along with plumed. If not, see <http://www.gnu.org/licenses/>.
21 : +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
22 : #include "Colvar.h"
23 : #include "core/PlumedMain.h"
24 : #include "core/ActionRegister.h"
25 : #include "tools/Torsion.h"
26 :
27 : namespace PLMD {
28 : namespace colvar {
29 :
30 : //+PLUMEDOC COLVAR PUCKERING
31 : /*
32 : Calculate sugar pseudorotation coordinates.
33 :
34 : This command can be used to calculate pseudorotations for the rings in sugars (puckers). It works for both
35 : 5-membered and 6-membered rings. Notice that there are two different implementations depending if
36 : one passes 5 or 6 atoms in the ATOMS keyword. This input tells plumed to print the puckering phase angle of the
37 : second nucleotide of a RNA molecule on file COLVAR.
38 :
39 : ```plumed
40 : #SETTINGS MOLFILE=regtest/basic/rt65/AA.pdb
41 : MOLINFO STRUCTURE=regtest/basic/rt65/AA.pdb MOLTYPE=rna
42 : puck: PUCKERING ATOMS=@sugar-2
43 : PRINT ARG=puck.phs FILE=COLVAR
44 : ```
45 :
46 : For 5-membered rings the implementation is the one discussed in the first of the papers in the bibliography below.
47 : This implementation is simple and can be used in RNA to distinguish C2'-endo and C3'-endo conformations.
48 : Both the polar coordinates (phs and amp) and the Cartesian coordinates (Zx and Zy) are provided.
49 : C2'-endo conformations have negative Zx, whereas C3'-endo conformations have positive Zy.
50 : The notation is consistent with the notation in that first paper.
51 : The five atoms should be provided as C4',O4',C1',C2',C3'.
52 : Notice that this is the same order that can be obtained using the [MOLINFO](MOLINFO.md) syntax (see example below).
53 :
54 : For 6-membered rings the implementation is the general Cremer-Pople one that is discussed in the second and third
55 : papers in the bibliography.
56 : This implementation provides both a triplet with Cartesian components (qx, qy, and qz)
57 : and a triplet of polar components (amplitude, phi, and theta).
58 : Applications of this particular implementation are yet to be published (paper in preparation).
59 :
60 : !!! note "sign error in earlier versions"
61 :
62 : The 6-membered ring implementation distributed with previous versions of PLUMED lead to
63 : qx and qy values that had an opposite sign with respect to those originally defined in the
64 : thid reference in the bibliograph below. The bug was fixed in version 2.5.
65 :
66 : */
67 : //+ENDPLUMEDOC
68 :
69 : class Puckering : public Colvar {
70 :
71 : public:
72 : explicit Puckering(const ActionOptions&);
73 : void calculate() override;
74 : static void registerKeywords(Keywords& keys);
75 : void calculate5m();
76 : void calculate6m();
77 : };
78 :
79 : PLUMED_REGISTER_ACTION(Puckering,"PUCKERING")
80 :
81 60 : void Puckering::registerKeywords(Keywords& keys) {
82 60 : Colvar::registerKeywords( keys );
83 120 : keys.remove("NOPBC");
84 60 : keys.add("atoms","ATOMS","the five or six atoms of the sugar ring in the proper order");
85 120 : keys.addOutputComponent("phs","default","scalar","Pseudorotation phase (5 membered rings)");
86 120 : keys.addOutputComponent("amp","default","scalar","Pseudorotation amplitude (5 membered rings)");
87 120 : keys.addOutputComponent("Zx","default","scalar","Pseudorotation x Cartesian component (5 membered rings)");
88 120 : keys.addOutputComponent("Zy","default","scalar","Pseudorotation y Cartesian component (5 membered rings)");
89 120 : keys.addOutputComponent("phi","default","scalar","Pseudorotation phase (6 membered rings)");
90 120 : keys.addOutputComponent("theta","default","scalar","Theta angle (6 membered rings)");
91 120 : keys.addOutputComponent("amplitude","default","scalar","Pseudorotation amplitude (6 membered rings)");
92 120 : keys.addOutputComponent("qx","default","scalar","Cartesian component x (6 membered rings)");
93 120 : keys.addOutputComponent("qy","default","scalar","Cartesian component y (6 membered rings)");
94 120 : keys.addOutputComponent("qz","default","scalar","Cartesian component z (6 membered rings)");
95 60 : keys.addDOI("10.1021/ct401013s");
96 60 : keys.addDOI("10.1021/ja00839a011");
97 60 : keys.addDOI("10.1021/ja068411o");
98 60 : }
99 :
100 56 : Puckering::Puckering(const ActionOptions&ao):
101 56 : PLUMED_COLVAR_INIT(ao) {
102 56 : std::vector<AtomNumber> atoms;
103 112 : parseAtomList("ATOMS",atoms);
104 56 : if(atoms.size()!=5 && atoms.size()!=6) {
105 1 : error("only for 5 or 6-membered rings");
106 : }
107 55 : checkRead();
108 :
109 55 : if(atoms.size()==5) {
110 54 : log.printf(" between atoms %d %d %d %d %d\n",atoms[0].serial(),atoms[1].serial(),atoms[2].serial(),atoms[3].serial(),atoms[4].serial());
111 1 : } else if(atoms.size()==6) {
112 1 : log.printf(" between atoms %d %d %d %d %d %d\n",atoms[0].serial(),atoms[1].serial(),atoms[2].serial(),atoms[3].serial(),atoms[4].serial(),atoms[5].serial());
113 : } else {
114 0 : error("ATOMS should specify 5 atoms");
115 : }
116 :
117 55 : if(atoms.size()==5) {
118 108 : addComponentWithDerivatives("phs");
119 108 : componentIsPeriodic("phs","-pi","pi");
120 108 : addComponentWithDerivatives("amp");
121 108 : componentIsNotPeriodic("amp");
122 108 : addComponentWithDerivatives("Zx");
123 108 : componentIsNotPeriodic("Zx");
124 108 : addComponentWithDerivatives("Zy");
125 108 : componentIsNotPeriodic("Zy");
126 1 : } else if(atoms.size()==6) {
127 2 : addComponentWithDerivatives("qx");
128 2 : componentIsNotPeriodic("qx");
129 2 : addComponentWithDerivatives("qy");
130 2 : componentIsNotPeriodic("qy");
131 2 : addComponentWithDerivatives("qz");
132 2 : componentIsNotPeriodic("qz");
133 2 : addComponentWithDerivatives("phi");
134 2 : componentIsPeriodic("phi","0","2pi");
135 2 : addComponentWithDerivatives("theta");
136 2 : componentIsNotPeriodic("theta");
137 2 : addComponentWithDerivatives("amplitude");
138 2 : componentIsNotPeriodic("amplitude");
139 : }
140 :
141 55 : log<<" Bibliography ";
142 55 : if(atoms.size()==5) {
143 108 : log<<plumed.cite("Huang, Giese, Lee, York, J. Chem. Theory Comput. 10, 1538 (2014)");
144 : }
145 55 : if(atoms.size()==6) {
146 2 : log<<plumed.cite("Cremer and Pople, J. Am. Chem. Soc. 97, 1354 (1975)");
147 : }
148 55 : log<<"\n";
149 :
150 55 : requestAtoms(atoms);
151 58 : }
152 :
153 : // calculator
154 397 : void Puckering::calculate() {
155 397 : makeWhole();
156 397 : if(getNumberOfAtoms()==5) {
157 294 : calculate5m();
158 : } else {
159 103 : calculate6m();
160 : }
161 397 : }
162 :
163 294 : void Puckering::calculate5m() {
164 :
165 : Vector d0,d1,d2,d3,d4,d5;
166 :
167 294 : d0=delta(getPosition(2),getPosition(1));
168 294 : d1=delta(getPosition(3),getPosition(2));
169 294 : d2=delta(getPosition(4),getPosition(3));
170 294 : d3=delta(getPosition(4),getPosition(3));
171 294 : d4=delta(getPosition(0),getPosition(4));
172 294 : d5=delta(getPosition(1),getPosition(0));
173 :
174 294 : Vector dd0,dd1,dd2,dd3,dd4,dd5;
175 :
176 : PLMD::Torsion t;
177 :
178 294 : double v1=t.compute(d0,d1,d2,dd0,dd1,dd2);
179 294 : double v3=t.compute(d3,d4,d5,dd3,dd4,dd5);
180 :
181 294 : double Zx=(v1+v3)/(2.0*std::cos(4.0*pi/5.0));
182 294 : double Zy=(v1-v3)/(2.0*std::sin(4.0*pi/5.0));
183 294 : double phase=std::atan2(Zy,Zx);
184 294 : double amplitude=std::sqrt(Zx*Zx+Zy*Zy);
185 :
186 : Vector dZx_dR[5];
187 : Vector dZy_dR[5];
188 :
189 294 : dZx_dR[0]=(dd5-dd4);
190 294 : dZx_dR[1]=(dd0-dd5);
191 294 : dZx_dR[2]=(dd1-dd0);
192 294 : dZx_dR[3]=(dd2+dd3-dd1);
193 294 : dZx_dR[4]=(dd4-dd3-dd2);
194 :
195 294 : dZy_dR[0]=(dd4-dd5);
196 294 : dZy_dR[1]=(dd0+dd5);
197 294 : dZy_dR[2]=(dd1-dd0);
198 294 : dZy_dR[3]=(dd2-dd3-dd1);
199 294 : dZy_dR[4]=(dd3-dd4-dd2);
200 :
201 1764 : for(unsigned j=0; j<5; j++) {
202 1470 : dZx_dR[j]*=(1.0/(2.0*std::cos(4.0*pi/5.0)));
203 : }
204 1764 : for(unsigned j=0; j<5; j++) {
205 1470 : dZy_dR[j]*=(1.0/(2.0*std::sin(4.0*pi/5.0)));
206 : }
207 :
208 294 : Vector dphase_dR[5];
209 1764 : for(unsigned j=0; j<5; j++) {
210 1470 : dphase_dR[j]=(1.0/(Zx*Zx+Zy*Zy))*(-Zy*dZx_dR[j] + Zx*dZy_dR[j]);
211 : }
212 :
213 294 : Vector damplitude_dR[5];
214 1764 : for(unsigned j=0; j<5; j++) {
215 1470 : damplitude_dR[j]=(1.0/amplitude)*(Zx*dZx_dR[j] + Zy*dZy_dR[j]);
216 : }
217 :
218 588 : Value* vzx=getPntrToComponent("Zx");
219 : vzx->set(Zx);
220 294 : setAtomsDerivatives (vzx,0, dZx_dR[0]);
221 294 : setAtomsDerivatives (vzx,1, dZx_dR[1]);
222 294 : setAtomsDerivatives (vzx,2, dZx_dR[2]);
223 294 : setAtomsDerivatives (vzx,3, dZx_dR[3]);
224 294 : setAtomsDerivatives (vzx,4, dZx_dR[4]);
225 294 : setBoxDerivativesNoPbc(vzx);
226 :
227 588 : Value* vzy=getPntrToComponent("Zy");
228 : vzy->set(Zy);
229 294 : setAtomsDerivatives (vzy,0, dZy_dR[0]);
230 294 : setAtomsDerivatives (vzy,1, dZy_dR[1]);
231 294 : setAtomsDerivatives (vzy,2, dZy_dR[2]);
232 294 : setAtomsDerivatives (vzy,3, dZy_dR[3]);
233 294 : setAtomsDerivatives (vzy,4, dZy_dR[4]);
234 294 : setBoxDerivativesNoPbc(vzy);
235 :
236 :
237 588 : Value* vph=getPntrToComponent("phs");
238 : vph->set(phase);
239 294 : setAtomsDerivatives (vph,0, dphase_dR[0]);
240 294 : setAtomsDerivatives (vph,1, dphase_dR[1]);
241 294 : setAtomsDerivatives (vph,2, dphase_dR[2]);
242 294 : setAtomsDerivatives (vph,3, dphase_dR[3]);
243 294 : setAtomsDerivatives (vph,4, dphase_dR[4]);
244 294 : setBoxDerivativesNoPbc(vph);
245 :
246 588 : Value* vam=getPntrToComponent("amp");
247 : vam->set(amplitude);
248 294 : setAtomsDerivatives (vam,0, damplitude_dR[0]);
249 294 : setAtomsDerivatives (vam,1, damplitude_dR[1]);
250 294 : setAtomsDerivatives (vam,2, damplitude_dR[2]);
251 294 : setAtomsDerivatives (vam,3, damplitude_dR[3]);
252 294 : setAtomsDerivatives (vam,4, damplitude_dR[4]);
253 294 : setBoxDerivativesNoPbc(vam);
254 :
255 :
256 294 : }
257 :
258 103 : void Puckering::calculate6m() {
259 :
260 103 : std::vector<Vector> r(6);
261 721 : for(unsigned i=0; i<6; i++) {
262 618 : r[i]=getPosition(i);
263 : }
264 :
265 103 : std::vector<Vector> R(6);
266 : Vector center;
267 721 : for(unsigned j=0; j<6; j++) {
268 618 : center+=r[j]/6.0;
269 : }
270 721 : for(unsigned j=0; j<6; j++) {
271 618 : R[j]=(r[j]-center);
272 : }
273 :
274 103 : Vector Rp,Rpp;
275 721 : for(unsigned j=0; j<6; j++) {
276 618 : Rp +=R[j]*std::sin(2.0/6.0*pi*j);
277 : }
278 721 : for(unsigned j=0; j<6; j++) {
279 618 : Rpp+=R[j]*std::cos(2.0/6.0*pi*j);
280 : }
281 :
282 103 : Vector n=crossProduct(Rp,Rpp);
283 : Vector nhat=n/modulo(n);
284 :
285 : Tensor dn_dRp=dcrossDv1(Rp,Rpp);
286 : Tensor dn_dRpp=dcrossDv2(Rp,Rpp);
287 :
288 103 : Tensor dnhat_dn= 1.0/modulo(n)*( Tensor::identity() - extProduct(nhat,nhat));
289 103 : Tensor dnhat_dRp=matmul(dnhat_dn,dn_dRp);
290 103 : Tensor dnhat_dRpp=matmul(dnhat_dn,dn_dRpp);
291 :
292 103 : std::vector<double> z(6);
293 721 : for(unsigned j=0; j<6; j++) {
294 618 : z[j]=dotProduct(R[j],nhat);
295 : }
296 :
297 103 : std::vector<std::vector<Vector> > dz_dR(6);
298 721 : for(unsigned j=0; j<6; j++) {
299 618 : dz_dR[j].resize(6);
300 : }
301 :
302 721 : for(unsigned i=0; i<6; i++)
303 4326 : for(unsigned j=0; j<6; j++) {
304 3708 : if(i==j) {
305 618 : dz_dR[i][j]+=nhat;
306 : }
307 3708 : dz_dR[i][j]+=matmul(R[i],dnhat_dRp)*std::sin(2.0/6.0*pi*j);
308 3708 : dz_dR[i][j]+=matmul(R[i],dnhat_dRpp)*std::cos(2.0/6.0*pi*j);
309 : }
310 :
311 : double B=0.0;
312 721 : for(unsigned j=0; j<6; j++) {
313 618 : B+=z[j]*std::cos(4.0/6.0*pi*j);
314 : }
315 :
316 103 : std::vector<Vector> dB_dR(6);
317 721 : for(unsigned i=0; i<6; i++)
318 4326 : for(unsigned j=0; j<6; j++) {
319 3708 : dB_dR[i]+=dz_dR[j][i]*std::cos(4.0/6.0*pi*j);
320 : }
321 : Vector Bsum;
322 721 : for(unsigned j=0; j<6; j++) {
323 618 : Bsum+=dB_dR[j];
324 : }
325 721 : for(unsigned j=0; j<6; j++) {
326 618 : dB_dR[j]-=Bsum/6.0;
327 : };
328 :
329 : double A=0.0;
330 721 : for(unsigned j=0; j<6; j++) {
331 618 : A+=z[j]*std::sin(4.0/6.0*pi*j);
332 : }
333 :
334 103 : std::vector<Vector> dA_dR(6);
335 721 : for(unsigned i=0; i<6; i++)
336 4326 : for(unsigned j=0; j<6; j++) {
337 3708 : dA_dR[i]+=dz_dR[j][i]*std::sin(4.0/6.0*pi*j);
338 : }
339 : Vector Asum;
340 721 : for(unsigned j=0; j<6; j++) {
341 618 : Asum+=dA_dR[j];
342 : }
343 721 : for(unsigned j=0; j<6; j++) {
344 618 : dA_dR[j]-=Asum/6.0;
345 : };
346 :
347 : double C=0.0;
348 721 : for(unsigned j=0; j<6; j++) {
349 618 : C+=z[j]*Tools::fastpow(-1.0,(j));
350 : }
351 :
352 103 : std::vector<Vector> dC_dR(6);
353 721 : for(unsigned i=0; i<6; i++)
354 4326 : for(unsigned j=0; j<6; j++) {
355 3708 : dC_dR[i]+=dz_dR[j][i]*Tools::fastpow(-1.0,(j));
356 : }
357 :
358 : Vector Csum;
359 721 : for(unsigned j=0; j<6; j++) {
360 618 : Csum+=dC_dR[j];
361 : }
362 721 : for(unsigned j=0; j<6; j++) {
363 618 : dC_dR[j]-=Csum/6.0;
364 : };
365 :
366 :
367 : // qx
368 103 : double qx = -A/std::sqrt(3);
369 :
370 : // qx derivaties
371 103 : std::vector<Vector> dqx_dR(6);
372 721 : for(unsigned j=0; j<6; j++) {
373 618 : dqx_dR[j]=-1/std::sqrt(3) * dA_dR[j];
374 : }
375 :
376 206 : Value* vqx=getPntrToComponent("qx");
377 : vqx->set(qx);
378 103 : setAtomsDerivatives (vqx,0, dqx_dR[0] );
379 103 : setAtomsDerivatives (vqx,1, dqx_dR[1] );
380 103 : setAtomsDerivatives (vqx,2, dqx_dR[2] );
381 103 : setAtomsDerivatives (vqx,3, dqx_dR[3] );
382 103 : setAtomsDerivatives (vqx,4, dqx_dR[4] );
383 103 : setAtomsDerivatives (vqx,5, dqx_dR[5] );
384 103 : setBoxDerivativesNoPbc(vqx);
385 :
386 : // qy
387 103 : double qy = B/std::sqrt(3);
388 :
389 : // qy derivatives
390 103 : std::vector<Vector> dqy_dR(6);
391 721 : for(unsigned j=0; j<6; j++) {
392 618 : dqy_dR[j]=1/std::sqrt(3) * dB_dR[j];
393 : }
394 :
395 206 : Value* vqy=getPntrToComponent("qy");
396 : vqy->set(qy);
397 103 : setAtomsDerivatives (vqy,0, dqy_dR[0] );
398 103 : setAtomsDerivatives (vqy,1, dqy_dR[1] );
399 103 : setAtomsDerivatives (vqy,2, dqy_dR[2] );
400 103 : setAtomsDerivatives (vqy,3, dqy_dR[3] );
401 103 : setAtomsDerivatives (vqy,4, dqy_dR[4] );
402 103 : setAtomsDerivatives (vqy,5, dqy_dR[5] );
403 103 : setBoxDerivativesNoPbc(vqy);
404 :
405 : // qz
406 103 : double qz = C/std::sqrt(6);
407 :
408 : // qz derivatives
409 103 : std::vector<Vector> dqz_dR(6);
410 721 : for(unsigned j=0; j<6; j++) {
411 618 : dqz_dR[j]=1/std::sqrt(6) * dC_dR[j];
412 : }
413 :
414 206 : Value* vqz=getPntrToComponent("qz");
415 : vqz->set(qz);
416 103 : setAtomsDerivatives (vqz,0, dqz_dR[0] );
417 103 : setAtomsDerivatives (vqz,1, dqz_dR[1] );
418 103 : setAtomsDerivatives (vqz,2, dqz_dR[2] );
419 103 : setAtomsDerivatives (vqz,3, dqz_dR[3] );
420 103 : setAtomsDerivatives (vqz,4, dqz_dR[4] );
421 103 : setAtomsDerivatives (vqz,5, dqz_dR[5] );
422 103 : setBoxDerivativesNoPbc(vqz);
423 :
424 :
425 : // PHASE
426 103 : double phi=std::atan2(-A,B);
427 :
428 : // PHASE DERIVATIVES
429 103 : std::vector<Vector> dphi_dR(6);
430 721 : for(unsigned j=0; j<6; j++) {
431 618 : dphi_dR[j]=1.0/(A*A+B*B) * (-B*dA_dR[j] + A*dB_dR[j]);
432 : }
433 :
434 206 : Value* vphi=getPntrToComponent("phi");
435 : vphi->set(phi);
436 103 : setAtomsDerivatives (vphi,0, dphi_dR[0] );
437 103 : setAtomsDerivatives (vphi,1, dphi_dR[1] );
438 103 : setAtomsDerivatives (vphi,2, dphi_dR[2] );
439 103 : setAtomsDerivatives (vphi,3, dphi_dR[3] );
440 103 : setAtomsDerivatives (vphi,4, dphi_dR[4] );
441 103 : setAtomsDerivatives (vphi,5, dphi_dR[5] );
442 103 : setBoxDerivativesNoPbc(vphi);
443 :
444 : // AMPLITUDE
445 103 : double amplitude=std::sqrt((2*(A*A+B*B)+C*C)/6);
446 :
447 : // AMPLITUDE DERIVATIES
448 103 : std::vector<Vector> damplitude_dR(6);
449 721 : for (unsigned j=0; j<6; j++) {
450 618 : damplitude_dR[j]=0.5*std::sqrt(2.0/6.0)/(std::sqrt(A*A+B*B+0.5*C*C)) * (2*A*dA_dR[j] + 2*B*dB_dR[j] + C*dC_dR[j]);
451 : }
452 :
453 206 : Value* vamplitude=getPntrToComponent("amplitude");
454 : vamplitude->set(amplitude);
455 103 : setAtomsDerivatives (vamplitude,0, damplitude_dR[0] );
456 103 : setAtomsDerivatives (vamplitude,1, damplitude_dR[1] );
457 103 : setAtomsDerivatives (vamplitude,2, damplitude_dR[2] );
458 103 : setAtomsDerivatives (vamplitude,3, damplitude_dR[3] );
459 103 : setAtomsDerivatives (vamplitude,4, damplitude_dR[4] );
460 103 : setAtomsDerivatives (vamplitude,5, damplitude_dR[5] );
461 103 : setBoxDerivativesNoPbc(vamplitude);
462 :
463 : // THETA
464 103 : double theta=std::acos( C / std::sqrt(2.*(A*A+B*B) +C*C ) );
465 :
466 : // THETA DERIVATIVES
467 103 : std::vector<Vector> dtheta_dR(6);
468 721 : for(unsigned j=0; j<6; j++) {
469 618 : dtheta_dR[j]=1.0/(3.0*std::sqrt(2)*amplitude*amplitude) * (C/(std::sqrt(A*A+B*B)) * (A*dA_dR[j] + B*dB_dR[j]) - std::sqrt(A*A+B*B)*dC_dR[j]);
470 : }
471 206 : Value* vtheta=getPntrToComponent("theta");
472 : vtheta->set(theta);
473 103 : setAtomsDerivatives (vtheta,0, dtheta_dR[0] );
474 103 : setAtomsDerivatives (vtheta,1, dtheta_dR[1] );
475 103 : setAtomsDerivatives (vtheta,2, dtheta_dR[2] );
476 103 : setAtomsDerivatives (vtheta,3, dtheta_dR[3] );
477 103 : setAtomsDerivatives (vtheta,4, dtheta_dR[4] );
478 103 : setAtomsDerivatives (vtheta,5, dtheta_dR[5] );
479 103 : setBoxDerivativesNoPbc(vtheta);
480 103 : }
481 :
482 :
483 : }
484 : }
485 :
486 :
487 :
|