44 #include <boost/algorithm/string.hpp>
45 #include <boost/tokenizer.hpp>
46 #include <boost/assign.hpp>
50 #include "libConfigUtils.hpp"
51 #include "conversionUtils.hpp"
60 using namespace boost;
61 using namespace boost::assign;
62 using namespace libconfig;
69 bool waveDescription::_debug =
false;
72 map<string,string> waveDescription::isobars = map_list_of
78 (
"rho(770)0",
"\\rho^0(770)")
79 (
"a1(1260)-",
"a_1^-(1260)")
80 (
"a2(1320)-",
"a_2^-(1320)")
81 (
"rho(1450)0",
"\\rho^0(1450)")
82 (
"rho(1700)0",
"\\rho^0(1700)")
83 (
"pi(1300)-",
"\\pi^-(1300)")
84 (
"pi(1800)-",
"\\pi^-(1800)")
85 (
"pi2(1670)-",
"\\pi^-_2(1670)")
86 (
"f0(1370)0",
"f_0^0(1370)")
87 (
"f0(1500)0",
"f_0^0(1500)")
88 (
"f0(1700)0",
"f_0^0(1700)")
89 (
"f1(1285)0",
"f_1^0(1285)")
90 (
"f1(1420)0",
"f_1^0(1420)")
91 (
"b1(1235)0",
"b_1^0(1235)")
92 (
"b1(1800)0",
"b_1^0(1800)")
93 (
"b0(1800)0",
"b_0^0(1800)")
94 (
"b2(1800)0",
"b_2^0(1800)")
95 (
"b1(1500)0",
"b_1^0(1500)")
96 (
"f2(1270)0",
"f_2^0(1270)")
97 (
"f2(1950)0",
"f_2^0(1950)")
98 (
"f2(1565)0",
"f_2^0(1565)")
99 (
"f2(2010)0",
"f_2^0(2010)")
100 (
"eta(1440)0" ,
"\\eta^0(1420)")
101 (
"eta2(1645)0",
"\\eta_2^0(1645)")
102 (
"eta1(1600)0",
"\\eta_1^0(1600)")
103 (
"pi1(1600)-",
"\\pi_1^-(1600)")
104 (
"rho3(1690)0",
"\\rho_3^0(1690)")
105 (
"rho(1600)0",
"\\rho^0(1600)");
108 waveDescription::waveDescription()
111 _keyFileParsed (false),
112 _keyFileLocalCopy(
"")
137 if (
this != &waveDesc) {
153 if (not parseLibConfigFile(keyFileName, *_key,
_debug)) {
154 printWarn <<
"problems reading key file '" << keyFileName <<
"'. "
155 <<
"cannot construct decay topology." << endl;
162 ifstream keyFile(keyFileName.c_str());
163 if (not keyFile or not keyFile.good()) {
164 printWarn <<
"cannot read from file '" << keyFileName <<
"'" << endl;
169 while(getline(keyFile, line))
181 typedef tokenizer<char_separator<char> > tokenizer;
182 char_separator<char> separator(
"\n");
184 unsigned int lineNumber = 0;
185 for (tokenizer::iterator
i = keyFileLines.begin();
i != keyFileLines.end(); ++
i)
186 out << setw(5) << ++lineNumber <<
" " << *
i << endl;
188 out <<
"key file contents string is empty" << endl;
195 const bool fromTemplate)
const
198 printWarn <<
"parsing was not successful. cannot construct decay topology." << endl;
206 const Setting& rootKey =
_key->getRoot();
207 printInfo <<
"constructing decay topology from key file" << endl;
210 const Setting* decayVertKey = findLibConfigGroup(rootKey,
"decayVertex");
211 if (not decayVertKey) {
212 printWarn <<
"cannot find 'wave' group. cannot construct decay topology." << endl;
217 const Setting* XQnKey = findLibConfigGroup(*decayVertKey,
"XQuantumNumbers", not fromTemplate);
220 if (not fromTemplate) {
221 printWarn <<
"cannot find 'XQuantumNumbers' group. cannot construct decay topology." << endl;
226 printDebug <<
"cannot find 'XQuantumNumbers' group. "
227 <<
"creating X particle with default properties." << endl;
233 printWarn <<
"problems constructing X particle. cannot construct decay topology." << endl;
240 printWarn <<
"problems constructing production vertex. cannot construct decay topology." << endl;
245 const Setting* XDecayKey = findLibConfigGroup(*decayVertKey,
"XDecay");
247 printWarn <<
"cannot find 'XDecay' group. cannot construct decay topology." << endl;
251 vector<isobarDecayVertexPtr> decayVertices;
252 vector<particlePtr> fsParticles;
254 printWarn <<
"problems constructing decay chain. cannot construct decay topology." << endl;
262 topo->calcIsobarCharges();
267 printSucc <<
"constructed decay topology from key file" << endl;
277 printWarn <<
"problems constructing decay topology. cannot construct decay amplitude." << endl;
289 printWarn <<
"null pointer to decay topology. cannot construct decay amplitude." << endl;
292 if (not topo->checkTopology() or not topo->checkConsistency()) {
293 printWarn <<
"decay topology has issues. cannot construct decay amplitude." << endl;
300 string formalism =
"helicity";
301 bool boseSymmetrize =
true;
302 bool isospinSymmetrize =
true;
303 bool useReflectivityBasis =
true;
305 const Setting& rootKey =
_key->getRoot();
306 const libconfig::Setting* amplitudeKey = findLibConfigGroup(rootKey,
"amplitude",
false);
308 if (amplitudeKey->lookupValue(
"formalism", formalism) and
_debug)
309 printDebug <<
"setting amplitude formalism to '" << formalism <<
"'" << endl;
310 if (amplitudeKey->lookupValue(
"boseSymmetrize", boseSymmetrize) and
_debug)
311 printDebug <<
"setting amplitude option 'boseSymmetrize' to "
312 << trueFalse(boseSymmetrize) << endl;
313 if (amplitudeKey->lookupValue(
"isospinSymmetrize", isospinSymmetrize) and
_debug)
314 printDebug <<
"setting amplitude option 'isospinSymmetrize' to "
315 << trueFalse(isospinSymmetrize) << endl;
316 if (amplitudeKey->lookupValue(
"useReflectivityBasis", useReflectivityBasis) and
_debug)
317 printDebug <<
"setting amplitude option 'useReflectivityBasis' to "
318 << trueFalse(useReflectivityBasis) << endl;
323 printDebug <<
"constructed amplitude '"<< amplitude->name() <<
"': "
324 << enDisabled(boseSymmetrize ) <<
" Bose symmetrization, "
325 << enDisabled(isospinSymmetrize ) <<
" isospin symmetrization, "
326 << enDisabled(useReflectivityBasis) <<
" reflectivity basis" << endl;
328 printWarn <<
"problems constructing decay amplitude." << endl;
331 amplitude->enableBoseSymmetrization (boseSymmetrize );
332 amplitude->enableIsospinSymmetrization(isospinSymmetrize );
333 amplitude->enableReflectivityBasis (useReflectivityBasis);
340 const bool newConvention,
343 ostringstream waveName;
346 printWarn <<
"decay topology has issues. cannot construct wave name." << endl;
352 waveName <<
"[" << spinQn(X.
isospin()) << parityQn(X.
G()) <<
","
353 << spinQn(X.
J()) << parityQn(X.
P()) << parityQn(X.
C()) <<
","
357 waveName << spinQn(X.
isospin()) << sign(X.
G())
358 << spinQn(X.
J()) << sign(X.
P()) << sign(X.
C())
370 waveName <<
"=[" << currentVertex->daughter1()->name();
373 (topo, newConvention,
374 static_pointer_cast<isobarDecayVertex>(topo.toVertex(currentVertex->daughter1())));
376 waveName <<
"[" << spinQn(currentVertex->L()) <<
"," << spinQn(currentVertex->S()) <<
"]";
378 waveName << currentVertex->daughter2()->name();
381 (topo, newConvention,
382 static_pointer_cast<isobarDecayVertex>(topo.toVertex(currentVertex->daughter2())));
385 waveName << ((currentVertex->parent()->charge() != 0) ? currentVertex->parent()->name()
386 : currentVertex->parent()->bareName());
388 if (not topo.
isFsVertex(currentVertex) and subGraph.nmbFsParticles() > 2)
391 (topo.toVertex(currentVertex->daughter1())))
392 <<
"_" << spinQn(currentVertex->L()) << spinQn(currentVertex->S()) <<
"_"
394 (topo.toVertex(currentVertex->daughter2())));
398 string name = waveName.str();
400 replace_all(name,
"(",
"_");
401 replace_all(name,
")",
"_");
403 replace_all(name,
"(",
"");
404 replace_all(name,
")",
"");
415 ostringstream waveLaTeX;
418 printWarn <<
"decay topology has issues. cannot construct wave LaTeX." << endl;
423 waveLaTeX << spinQn(X.
isospin()) <<
"^{"<< parityQn(X.
G()) <<
"}"
424 << spinQn(X.
J()) <<
"^{" << parityQn(X.
P()) << parityQn(X.
C()) <<
"}"
428 else if(not (topo.
isFsParticle(currentVertex->daughter1())
436 string dau1=
isobars[currentVertex->daughter1()->name()];
438 dau1=
"{\\bf ";dau1+=currentVertex->daughter1()->name();dau1+=
"}";
440 if(!isXdecay)waveLaTeX <<
"\\rightarrow\\left\\{ ";
445 static_pointer_cast<isobarDecayVertex>(topo.toVertex(currentVertex->daughter1())));
447 waveLaTeX <<
"\\ells{" << spinQn(currentVertex->L()) <<
"}{" << spinQn(currentVertex->S()) <<
"}";
449 string dau2=
isobars[currentVertex->daughter2()->name()];
451 dau2=
"{\\bf ";dau2+=currentVertex->daughter2()->name();dau2+=
"}"; }
456 static_pointer_cast<isobarDecayVertex>(topo.toVertex(currentVertex->daughter2())));
457 if(!isXdecay)waveLaTeX <<
"\\right\\} ";
459 return waveLaTeX.str();
470 printWarn <<
"problems parsing key file string:" << endl;
472 cout <<
" cannot construct decay topology." << endl;
487 printDebug <<
"reading X quantum numbers from '" << XQnKey.getPath() <<
"':" << endl;
489 map<string, int> mandatoryXQn, optionalXQn;
490 mandatoryXQn[
"isospin" ];
496 optionalXQn [
"refl" ];
497 optionalXQn [
"baryonNmb" ];
498 optionalXQn [
"strangeness"];
499 optionalXQn [
"charm" ];
500 optionalXQn [
"beauty" ];
502 for (map<string, int>::iterator
i = mandatoryXQn.begin();
i != mandatoryXQn.end(); ++
i)
503 if (not XQnKey.lookupValue(
i->first,
i->second)) {
504 printWarn <<
"cannot find integer field '" <<
i->first <<
"in "
505 <<
"'" << XQnKey.getPath() <<
"'" << endl;
508 for (map<string, int>::iterator
i = optionalXQn.begin();
i != optionalXQn.end(); ++
i)
509 if (not XQnKey.lookupValue(
i->first,
i->second))
512 printWarn <<
"cannot find X quantum numbers. cannot construct decay topology." << endl;
517 mandatoryXQn[
"isospin"], optionalXQn[
"G"],
518 mandatoryXQn[
"J"], mandatoryXQn[
"P"], optionalXQn[
"C"],
519 mandatoryXQn[
"M"], optionalXQn[
"refl"]);
520 X->setBaryonNmb(optionalXQn[
"baryonNmb"]);
521 X->setSCB(optionalXQn[
"strangeness"], optionalXQn[
"charm"], optionalXQn[
"beauty"]);
523 printDebug <<
"constructed X particle: " << X->qnSummary() << endl;
530 const string& vertType,
535 if ((vertType ==
"diffractiveDissVertex") or (vertType ==
"leptoProductionVertex")) {
536 const string prodKinParticleNames[] = {
"beam",
"target",
"recoil"};
537 map<string, particlePtr> prodKinParticles;
538 for (
unsigned int i = 0;
i <
sizeof(prodKinParticleNames) /
sizeof(
string); ++
i)
539 prodKinParticles[prodKinParticleNames[
i]] =
particlePtr();
541 const Setting* beamParticleKey = 0;
542 for (map<string, particlePtr>::iterator
i = prodKinParticles.begin();
543 i != prodKinParticles.end(); ++
i) {
544 const Setting* particleKey = findLibConfigGroup(prodVertKey,
i->first,
545 (
i->first !=
"recoil") ?
true :
false);
547 if (
i->first ==
"beam")
548 beamParticleKey = particleKey;
551 }
else if (
i->first !=
"recoil")
555 if (vertType ==
"diffractiveDissVertex")
557 X, prodKinParticles[
"recoil"]);
558 else if (vertType ==
"leptoProductionVertex" ) {
560 X, prodKinParticles[
"recoil"]);
561 double beamLongPol = 0;
562 if ((beamParticleKey->lookupValue(
"longPol", beamLongPol))) {
564 printDebug <<
"setting polarization of beam " << prodKinParticles[
"beam"]->qnSummary()
565 <<
" to " << beamLongPol << endl;
567 printWarn <<
"no polarization is given for beam " << prodKinParticles[
"beam"]->qnSummary()
568 <<
". assuming unpolarized beam." << endl;
573 printWarn <<
"unknown production vertex type '" << vertType <<
"'" << endl;
575 if (success and prodVert)
576 printDebug <<
"constructed " << *prodVert << endl;
578 printWarn <<
"problems constructing production vertex of type '" << vertType <<
"'" << endl;
590 const Setting* prodVertKey = findLibConfigGroup(rootKey,
"productionVertex");
591 if (not prodVertKey) {
592 printWarn <<
"cannot find 'productionVertex' group" << endl;
596 printDebug <<
"reading production vertex from '" << prodVertKey->getPath() <<
"':" << endl;
600 if (not prodVertKey->lookupValue(
"type", vertType)) {
601 printWarn <<
"cannot find 'type' entry in '" << prodVertKey->getPath() <<
"'" << endl;
606 return (prodVert) ?
true :
false;
613 const bool requirePartInTable)
616 printDebug <<
"reading particle information from '" << particleKey.getPath() <<
"':" << endl;
618 if (particleKey.lookupValue(
"name", name)) {
621 if (particleKey.lookupValue(
"spinProj", spinProj))
622 particle->setSpinProj(spinProj);
624 printDebug <<
"created particle " << particle->qnSummary() << flush;
626 if (particleKey.lookupValue(
"index", index)) {
627 particle->setIndex(index);
629 cout <<
" with index [" << index <<
"]" << flush;
635 printWarn <<
"cannot construct particle from entry '" << particleKey.getPath() <<
"'. "
636 <<
"name field is missing." << endl;
647 if ( (massDepType ==
"BreitWigner")
648 or (massDepType ==
""))
650 else if (massDepType ==
"flat")
652 else if (massDepType ==
"f_0(980)")
654 else if (massDepType ==
"piPiSWaveAuMorganPenningtonM")
656 else if (massDepType ==
"piPiSWaveAuMorganPenningtonVes")
658 else if (massDepType ==
"piPiSWaveAuMorganPenningtonKachaev")
660 else if (massDepType ==
"rhoPrime")
663 printWarn <<
"unknown mass dependence '" << massDepType <<
"'. using Breit-Wigner." << endl;
673 vector<isobarDecayVertexPtr>& decayVertices,
674 vector<particlePtr>& fsParticles,
675 const bool fromTemplate)
678 printDebug <<
"reading decay vertex information from '" << parentKey.getPath() <<
"':" << endl;
681 const Setting* fsPartKeys = findLibConfigList(parentKey,
"fsParticles",
false);
682 vector<particlePtr> fsDaughters;
684 for (
int i = 0;
i < fsPartKeys->getLength(); ++
i) {
687 fsDaughters.push_back(p);
688 fsParticles.push_back(p);
693 const Setting* isobarKeys = findLibConfigList(parentKey,
"isobars",
false);
694 vector<particlePtr> isobarDaughters;
696 for (
int i = 0;
i < isobarKeys->getLength(); ++
i) {
699 isobarDaughters.push_back(p);
703 decayVertices, fsParticles, fromTemplate);
706 const unsigned int nmbDaughters = fsDaughters.size() + isobarDaughters.size();
707 if (nmbDaughters != 2) {
708 printWarn <<
"cannot construct isobar vertex, because number of daughters "
709 <<
"(" << nmbDaughters <<
") in '" << parentKey.getPath() <<
"' "
710 <<
"is not 2" << endl;
718 if (( not parentKey.lookupValue(
"L", L)
719 or not parentKey.lookupValue(
"S", S)) and not fromTemplate)
720 printWarn <<
"Either L or S are not specified in '" << parentKey.getPath() <<
"'. "
721 <<
"using zero." << endl;
725 if (parentParticle->bareName() !=
"X") {
726 string massDepType =
"";
727 const Setting* massDepKey = findLibConfigGroup(parentKey,
"massDep",
false);
729 massDepKey->lookupValue(
"name", massDepType);
736 if ((fsDaughters.size() == 1) and (isobarDaughters.size() == 1)) {
737 if (fsPartKeys->getIndex() < isobarKeys->getIndex()) {
738 daughters[0] = fsDaughters [0];
739 daughters[1] = isobarDaughters[0];
741 daughters[0] = isobarDaughters[0];
742 daughters[1] = fsDaughters [0];
744 }
else if (fsDaughters.size() == 2)
745 daughters = fsDaughters;
746 else if (isobarDaughters.size() == 2)
747 daughters = isobarDaughters;
751 daughters[1], L, S, massDep));
753 printDebug <<
"constructed " << *decayVertices.back() << endl;
763 if (formalismType ==
"helicity")
765 else if (formalismType ==
"canonical")
768 printWarn <<
"unknown amplitude formalism '" << formalismType <<
"'. "
769 <<
"using helicity formalism." << endl;
780 const string prodVertName = prodVert->name();
781 if ((prodVertName ==
"diffractiveDissVertex") or (prodVertName ==
"leptoProductionVertex")) {
783 printDebug <<
"setting keys for " << *prodVert << endl;
784 prodVertKey.add(
"type", Setting::TypeString) = prodVertName;
785 map<string, particlePtr> prodKinParticles;
786 if (prodVertName ==
"diffractiveDissVertex") {
788 prodKinParticles[
"beam" ] = vert->beam();
789 prodKinParticles[
"target"] = vert->target();
790 if (vert->recoil()->name() != vert->target()->name())
791 prodKinParticles[
"recoil"] = vert->recoil();
792 }
else if (prodVertName ==
"leptoProductionVertex") {
794 prodKinParticles[
"beam" ] = vert->beamLepton();
795 prodKinParticles[
"target"] = vert->target();
796 if (vert->recoil()->name() != vert->target()->name())
797 prodKinParticles[
"recoil"] = vert->recoil();
800 Setting* beamParticleKey = 0;
801 for (map<string, particlePtr>::iterator
i = prodKinParticles.begin();
802 i != prodKinParticles.end(); ++
i) {
803 Setting& particleKey = prodVertKey.add(
i->first, Setting::TypeGroup);
804 particleKey.add(
"name", Setting::TypeString) =
i->second->name();
805 if (
i->first ==
"beam")
806 beamParticleKey = &particleKey;
808 if ((prodVertName ==
"leptoProductionVertex") and beamParticleKey)
809 beamParticleKey->add(
"longPol", Setting::TypeFloat)
813 printWarn <<
"setting of keys for production vertex of this type is not yet implemented:"
814 << *prodVert << endl;
825 printDebug <<
"setting quantum number keys for " << X.
qnSummary() << endl;
826 XQnKey.add(
"isospin", Setting::TypeInt) = X.
isospin();
828 XQnKey.add(
"G", Setting::TypeInt) = X.
G();
829 XQnKey.add(
"J", Setting::TypeInt) = X.
J();
830 XQnKey.add(
"P", Setting::TypeInt) = X.
P();
832 XQnKey.add(
"C", Setting::TypeInt) = X.
C();
833 XQnKey.add(
"M", Setting::TypeInt) = X.
spinProj();
835 XQnKey.add(
"refl", Setting::TypeInt) = X.
reflectivity();
837 XQnKey.add(
"baryonNmb", Setting::TypeInt) = X.
baryonNmb();
839 XQnKey.add(
"strangeness", Setting::TypeInt) = X.
strangeness();
841 XQnKey.add(
"charm", Setting::TypeInt) = X.
charm();
843 XQnKey.add(
"beauty", Setting::TypeInt) = X.
beauty();
852 const string massDepName = massDep.
name();
853 if (massDepName ==
"flatMassDependence")
856 else if (massDepName ==
"relativisticBreitWigner")
861 printDebug <<
"setting key for '" << massDep <<
"' mass dependence to "
862 <<
"'" << massDepName <<
"'" << endl;
863 Setting& massDepKey = isobarDecayKey.add(
"massDep", Setting::TypeGroup);
864 massDepKey.add(
"name", Setting::TypeString) = massDepName;
876 printDebug <<
"setting keys for decay " << vert << endl;
878 vector<particlePtr> fsParticles;
883 fsParticles.push_back(part);
885 isobars.push_back(part);
888 if (isobars.size() > 0) {
889 Setting& isobarsKey = parentDecayKey.add(
"isobars", Setting::TypeList);
890 for (
unsigned int i = 0;
i < isobars.size(); ++
i) {
891 Setting& isobarKey = isobarsKey.add(Setting::TypeGroup);
892 isobarKey.add(
"name", Setting::TypeString) = isobars[
i]->name();
894 *static_pointer_cast<isobarDecayVertex>(topo.toVertex(isobars[
i]))))
898 parentDecayKey.add(
"L", Setting::TypeInt) = (
int)vert.
L();
899 parentDecayKey.add(
"S", Setting::TypeInt) = (
int)vert.
S();
900 if (fsParticles.size() > 0) {
901 Setting& fsParticlesKey = parentDecayKey.add(
"fsParticles", Setting::TypeList);
902 for (
unsigned int i = 0;
i < fsParticles.size(); ++
i) {
903 Setting& fsParticleKey = fsParticlesKey.add(Setting::TypeGroup);
904 fsParticleKey.add(
"name", Setting::TypeString) = fsParticles[
i]->name();
914 const bool setProdVert)
917 printWarn <<
"decay topology has issues. cannot write key file." << endl;
921 printDebug <<
"setting keys for " << topo;
923 Setting& prodVertKey = rootKey.add(
"productionVertex", Setting::TypeGroup);
926 Setting& decayVertKey = rootKey.add (
"decayVertex", Setting::TypeGroup);
927 Setting& XQnKey = decayVertKey.add(
"XQuantumNumbers", Setting::TypeGroup);
928 Setting& XDecayKey = decayVertKey.add(
"XDecay", Setting::TypeGroup);
930 printWarn <<
"problems setting X quantum numbers" << endl;
933 if (not
setXDecayKeys(XDecayKey, topo, *(topo.XIsobarDecayVertex()))) {
934 printWarn <<
"problems setting X decay" << endl;
946 printDebug <<
"setting amplitude keys." << endl;
947 string formalism =
"";
948 const string amplitudeName = amplitude.
name();
949 if (amplitudeName ==
"isobarCanonicalAmplitude") {
950 formalism =
"canonical";
951 }
else if (amplitudeName !=
"isobarHelicityAmplitude") {
952 printWarn <<
"unknown amplitude type '" << amplitudeName <<
"'" << endl;
955 if (formalism !=
"") {
957 printDebug <<
"setting 'formalism' key for '" << amplitudeName <<
"' to "
958 <<
"'" << formalism <<
"'" << endl;
959 amplitudeKey.add(
"formalism", Setting::TypeString) = formalism;
962 amplitudeKey.add(
"boseSymmetrize", Setting::TypeBoolean) =
false;
964 amplitudeKey.add(
"isospinSymmetrize", Setting::TypeBoolean) =
false;
966 amplitudeKey.add(
"useReflectivityBasis", Setting::TypeBoolean) =
false;
974 const bool setProdVert)
977 printInfo <<
"setting keys for "<< amplitude;
979 printWarn <<
"problems setting keys for decay topology" << endl;
982 Setting& amplitudeKey = rootKey.add(
"amplitude", Setting::TypeGroup);
984 printWarn <<
"problems setting amplitude paramaters" << endl;
994 const bool writeProdVert)
997 Setting& rootKey = key.getRoot();
999 printWarn <<
"problems writing keys for decay topology. cannot write key file." << endl;
1003 key.write(&outStream);
1004 }
catch (
const FileIOException& ioEx) {
1005 printWarn <<
"I/O error while writing key file" << endl;
1015 const bool writeProdVert)
1018 Setting& rootKey = key.getRoot();
1020 printWarn <<
"problems writing keys for amplitude. cannot write key file." << endl;
1024 key.write(&outStream);
1025 }
catch (
const FileIOException& ioEx) {
1026 printWarn <<
"I/O error while writing key file" << endl;